﻿using Acorisoft.FutureGL.MigaDB.Data.DataParts;
using Acorisoft.FutureGL.MigaDB.Documents;
using KinonekoSoftware.CodariaDB.Documents.Metadatas;
using KinonekoSoftware.CodariaDB.Documents.Personalities;
using KinonekoSoftware.CodariaDB.Documents.Templates;
using LiteDB;
using Metadata = Acorisoft.FutureGL.MigaDB.Data.Metadatas.Metadata;
using NewDataPart = KinonekoSoftware.CodariaDB.Documents.DataParts.DataPart;
using OldDataPart = Acorisoft.FutureGL.MigaDB.Data.DataParts.DataPart;
using NewSurvey = KinonekoSoftware.CodariaDB.Documents.Personalities.Survey;
using OldSurvey = Acorisoft.FutureGL.MigaDB.Data.DataParts.Survey;
using DatabaseNames = KinonekoSoftware.CodariaDB.Utils.CollectionNames;

namespace KinonekoSoftware.Studio.Utils.Transformers
{
    public sealed class InstanceTransformer : Transformer
    {
        private const string OldCollectionName = "doc";
        private const string NewCollectionName = DatabaseNames.InstanceDB;

        public override void Migrate(TransformContext context)
        {
            if (!context.OldRepo.CollectionExists(OldCollectionName))
            {
                return;
            }

            var newRepo                 = context.NewRepo;
            var oldCollection           = context.OldRepo.GetCollection<Document>(OldCollectionName);
            var newCollection           = newRepo.GetCollection<Instance>(NewCollectionName);
            var instanceCacheCollection = newRepo.GetCollection<InstanceCache>(DatabaseNames.Cache_InstanceDB);
            var partCollection          = newRepo.GetCollection<NewDataPart>(DatabaseNames.DataPartDB);
            var variantCollection       = newRepo.GetCollection<Variant>(DatabaseNames.VariantDB);
            var templateCollection      = newRepo.GetCollection<InstanceTemplate>(DatabaseNames.Template_InstanceDB);
            var dictionary              = new Dictionary<Type, NewDataPart>();

            foreach (var document in oldCollection.FindAll())
            {
                var oldID    = document.Id;
                var type     = TransformerHelper.GetInstanceType(document.Type);
                var template = templateCollection.FindOne(x => !x.UseCustomType && x.BuiltinType == type);

                if (!context.DocumentMapper.TryGetValue(oldID, out var newID))
                {
                    newID = ID.Get();
                }

                var instance = new Instance
                {
                    Id       = newID,
                    Intro    = document.Intro,
                    Name     = document.Name,
                    Template = template,
                    Type     = type,
                };

                //
                // 处理DataPart
                var parts = document.Parts.Select(oldPart => Transform(
                                                                       newID,
                                                                       context.NewRepoDir,
                                                                       context.OldRepoDir,
                                                                       dictionary,
                                                                       oldPart,
                                                                       newRepo)).ToList();
                var set = parts.Select(x => x.Type).ToHashSet();

                foreach (var definition in template.Definitions)
                {
                    if (set.Contains(definition.Type))
                    {
                        continue;
                    }

                    //
                    //
                    var part = PartFactory.Create(newID, definition.Type, instanceCacheCollection.FindById(newID), false);

                    if (part is null)
                    {
                        Xplat.Debug($"无法创建数据部件，{definition.Type}类型的部件缺少映射或者实现");
                        continue;
                    }

                    //
                    //
                    parts.Add(part);

                }

                //
                //
                partCollection.Insert(parts);

                //
                // 处理Metadata
                foreach (var variant in document.Metas.Select(meta => Transform(newID, meta)))
                {
                    variantCollection.Insert(variant);
                }

                newCollection.Insert(instance);
            }
        }

        private static NewDataPart Transform(
            string                        documentID,
            string                        newRepoDir,
            string                        oldRepoDir,
            Dictionary<Type, NewDataPart> dictionary,
            OldDataPart                   part,
            LiteDatabase                  newRepo)
        {
            if (part is PartOfBasic pob)
            {
                var property = pob.Buckets.Select(x => Transform(x.Key, x.Value)).Where(LambdaStatic.NotNull);
                var cb = new Part_CustomBasic
                {
                    Id         = ID.Get(),
                    DocumentID = documentID,
                    Blocks     = new List<CompositeParagraph>(),
                    Inlines    = new List<CompositeItem>(),
                };

                foreach (var item in property)
                {
                    if (item is CompositeParagraph cp)
                    {
                        cb.Blocks.Add(cp);
                    }
                    else
                    {
                        cb.Inlines.Add(item);
                    }
                }

                dictionary.TryAdd(cb.GetType(), cb);
                return cb;
            }

            if (part is PartOfAlbum poa)
            {

                if (poa.Items is null)
                {
                    return null;
                }

                var cd = new Part_CharacterDetail
                {
                    Id          = ID.Get(),
                    DocumentID  = documentID,
                    Images      = new List<ImageRes>(),
                    Worships    = new List<Worship>(),
                    Appearances = new List<SurveySets>(),
                    Behaviors   = new List<SurveySets>(),
                };

                var newGravatarDirectory = Path.Combine(newRepoDir, "Images");
                var oldGravatarDirectory = Path.Combine(oldRepoDir, "Image");

                foreach (var image in poa.Items)
                {
                    var src = Path.Combine(oldGravatarDirectory, image.Source);
                    var imgRes = new ImageRes
                    {
                        Id          = ID.Get(),
                        Title       = image.Name,
                        Description = TextSR.Parameter_Untitled,
                        ImageType   = ImageResType.HorizontalOrientation,
                        ImageID     = Transform(image.Source),
                    };

                    //
                    //
                    if (File.Exists(src))
                    {
                        File.Move(
                                  src,
                                  Path.Combine(newGravatarDirectory, $"{imgRes.ImageType}.png"));
                    }

                    //
                    //
                    cd.Images.Add(imgRes);
                }

                cd.Images.AddMany(poa.Items.Select(x => new ImageRes
                {
                    Id          = ID.Get(),
                    Title       = x.Name,
                    Description = TextSR.Parameter_Untitled,
                    ImageType   = ImageResType.HorizontalOrientation,
                    ImageID     = Transform(x.Source),
                }), true);

                dictionary.TryAdd(cd.GetType(), cd);
            }

            if (part is PartOfSurvey pos2)
            {
                if (pos2.Items is null)
                {
                    return null;
                }

                var cp = new Part_Personality
                {
                    Id         = ID.Get(),
                    DocumentID = documentID,
                    Surveys    = new List<SurveySets>(pos2.Items.Select(Transform)),
                };



                dictionary.TryAdd(cp.GetType(), cp);
                return cp;
            }

            return null;
        }

        private static SurveySets Transform(SurveySet target)
        {
            if (target is null)
            {
                return null;
            }

            var ss = new SurveySets
            {
                Id    = ID.Get(),
                Name  = target.Name,
                Intro = target.Intro,
                Items = new ObservableCollection<NewSurvey>(target.Items.Select(Transform))
            };

            return ss;
        }

        private static NewSurvey Transform(OldSurvey target)
        {
            if (target is null)
            {
                return null;
            }

            var ss = new NewSurvey
            {
                Id    = ID.Get(),
                Name  = target.Name,
                Intro = target.Intro,
                Value = target.Value,
            };

            return ss;
        }

        private static string Transform(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return null;
            }

            //
            // thumb_sUJjElh8vkCqpIXFrqsrmw
            return id.AsSpan().Slice(6, id.Length - 10).ToString();
        }


        private static CompositeItem Transform(string metadata, string value)
        {
            return metadata switch
            {
                "@name"     => InstanceTemplateGenerator.Property("名字", metadata, true, value),
                "@gender"   => InstanceTemplateGenerator.Property("性别", KnownMetadatas.Age, true, value),
                "@birth"    => InstanceTemplateGenerator.Property("生日", KnownMetadatas.Birthday, true, value),
                "@age"      => InstanceTemplateGenerator.Property("年龄", metadata, true, value),
                "@height"   => InstanceTemplateGenerator.Property("身高", metadata, true, value),
                "@weight"   => InstanceTemplateGenerator.Property("体重", metadata, true, value),
                "@nickname" => InstanceTemplateGenerator.Property("别名", metadata, true, value),
                "@race"     => InstanceTemplateGenerator.Property("种族", KnownMetadatas.Species, true, value),
                "@country"  => InstanceTemplateGenerator.Property("国家", metadata, true, value),
                "@intro"    => InstanceTemplateGenerator.Paragraph("简介", metadata, true, value),
                "@death"    => InstanceTemplateGenerator.ToggleSwitch("是否死亡", metadata, true, bool.TryParse(value, out var n) && n),
                _           => null,
            };
        }

        private static StringVariant Transform(string documentID, Acorisoft.FutureGL.MigaDB.Data.Metadatas.Metadata metadata)
        {
            return new StringVariant
            {
                Id         = ID.Get(),
                DocumentID = documentID,
                Metadata   = metadata.Name,
                Value      = metadata.Value,
                Type       = VariantType.String
            };
        }
    }
}